package com.starblink.basic.style.view.border


import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.SweepGradient
import android.util.AttributeSet
import androidx.annotation.ColorInt
import androidx.annotation.Px
import androidx.appcompat.widget.AppCompatImageView
import com.starblink.basic.style.R
import com.starblink.basic.style.view.SafeImageView
import com.starblink.basic.style.view.border.internal.*
import com.starblink.basic.style.view.border.internal.arrayPositions
import com.starblink.basic.style.view.border.internal.dp
import com.starblink.basic.style.view.border.internal.getEnum
import com.starblink.basic.style.view.border.internal.viewProperty
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlin.coroutines.CoroutineContext

/**
 * BorderImageView supports segmented style images, borders, indicators, and initials.
 */
class BorderImageView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
) : SafeImageView(context, attrs, defStyleAttr), CoroutineScope {

    private val borderPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.STROKE }
    private val backgroundPaint = Paint().apply { style = Paint.Style.FILL }

    @get:Px
    var borderWidth: Int by viewProperty(3.dp)

    @get:ColorInt
    var borderColor: Int by viewProperty(Color.WHITE)

    var borderColorArray: IntArray by viewProperty(intArrayOf())

    @get:Px
    var borderRadius: Float by viewProperty(6.dp.toFloat())

    var shape: BorderShape by viewProperty(BorderShape.CIRCLE)


    override val coroutineContext: CoroutineContext =
        SupervisorJob() + Dispatchers.Main

    init {
        initAttributes(attrs, defStyleAttr)
    }

    private fun initAttributes(attrs: AttributeSet?, defStyleAttr: Int) {
        attrs ?: return
        context.obtainStyledAttributes(attrs, R.styleable.BorderImageView, defStyleAttr, 0)
            .let { typedArray ->
                try {
                    borderWidth = typedArray.getDimensionPixelSize(
                        R.styleable.BorderImageView_borderWidth, borderWidth
                    )
                    borderColor = typedArray.getColor(
                        R.styleable.BorderImageView_borderColor, borderColor
                    )
                    borderColorArray = typedArray.getIntArray(
                        R.styleable.BorderImageView_borderColorArray, intArrayOf()
                    )
                    borderRadius = typedArray.getDimension(
                        R.styleable.BorderImageView_borderRadius,
                        borderRadius
                    )
                    shape = typedArray.getEnum<BorderShape>(
                        R.styleable.BorderImageView_borderShape,
                        shape
                    )
                } catch (e: Throwable) {
                    e.printStackTrace()
                } finally {
                    typedArray.recycle()
                }
            }


        /*val padding = (borderWidth - AVATAR_SIZE_EXTRA).coerceAtLeast(0)
        setPadding(
            padding + paddingLeft,
            padding + paddingTop,
            padding + paddingRight,
            padding + paddingBottom
        )*/
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {

        /*val width = resolveSize(0, widthMeasureSpec)
        val height = resolveSize(0, heightMeasureSpec)
        val avatarViewSize = width.coerceAtMost(height)
        setMeasuredDimension(avatarViewSize, avatarViewSize)*/
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

    }

    override fun onDraw(canvas: Canvas) {
        applyPaintStyles()
        super.onDraw(canvas)
        drawBorder(canvas)
    }


    private fun applyPaintStyles() {
        borderPaint.color = borderColor
        borderPaint.strokeWidth = borderWidth.toFloat()
    }

    /** Draws a border to . */
    private fun drawBorder(canvas: Canvas) {
        if (borderWidth == 0) return

        if (shape == BorderShape.ROUNDED_RECT) {
            canvas.drawRoundRect(
                BORDER_OFFSET,
                BORDER_OFFSET,
                width.toFloat() - BORDER_OFFSET,
                height.toFloat() - BORDER_OFFSET,
                borderRadius,
                borderRadius,
                borderPaint.applyGradientShader(borderColorArray, width / 2f, height / 2f)
            )
        } else {
            canvas.drawCircle(
                width / 2f,
                height / 2f,
                width / 2f - borderWidth / 2,
                borderPaint.applyGradientShader(borderColorArray, width / 2f, height / 2f)
            )
        }
    }

    private fun drawColor(canvas: Canvas) {
        if (shape == BorderShape.ROUNDED_RECT) {
            canvas.drawRoundRect(
                0F,
                0F,
                width.toFloat(),
                height.toFloat(),
                borderRadius,
                borderRadius,
                backgroundPaint
            )
        } else {
            canvas.drawCircle(
                width / 2f,
                height / 2f,
                width / 2f,
                backgroundPaint
            )
        }
    }


    /** Apply gradient shader to a [Paint]. */
    private fun Paint.applyGradientShader(colorArray: IntArray, cx: Float, cy: Float): Paint =
        apply {
            if (colorArray.isNotEmpty()) {
                shader = SweepGradient(
                    cx,
                    cy,
                    colorArray,
                    colorArray.arrayPositions
                )
            }
        }

    override fun onDetachedFromWindow() {
        coroutineContext.cancel()
        super.onDetachedFromWindow()
    }

    internal companion object {

        internal const val AVATAR_SIZE_EXTRA = 1

        private const val BORDER_OFFSET = 4F
    }
}
